/*****************************************************
** Author:
** Date: 2019-11-13
*
*****************************************************/

#ifndef __MPLINK_H_
#define __MPLINK_H_

#ifdef __cplusplus
extern "C"{
#endif

/*
 *	memory pool link
 */
struct mplink
{
	struct mplink *next;
	void *ptr; // user payload
};

static inline void mplink_init(struct mplink *head, int depth, \
				struct mplink **pfree, struct mplink **pusing, \
				void *ptr, int typesize)
{
	memset(head, 0x0, sizeof(struct mplink) * depth);

	int i;
	for (i = 0; i < (depth - 1); ++i) {
		head[i].next = &head[i+1];
		head[i].ptr = ptr + i * typesize;
	}
	head[i].next = NULL;
	head[i].ptr = ptr + i * typesize;

	*pfree = head;
	*pusing = NULL;
}

static inline void *mplink_new(struct mplink **pfree, struct mplink **pusing)
{
	if (*pfree == NULL) {
		return NULL;
	}

	struct mplink *pnew = *pfree;
	*pfree = pnew->next;

	pnew->next = *pusing;
	*pusing = pnew;

	return pnew->ptr;
}

#if 0
static inline int mplink_del(struct mplink **pfree, struct mplink **pusing, void *ptr)
{
	if (*pusing == NULL)
		return -1;

	// find the mplink of 'ptr'
	struct mplink *pdel = *pusing;
	while (pdel != NULL && pdel->ptr != ptr) {
		pdel = pdel->next;
	}
	if (pdel == NULL)
		return -2;

	if (pdel == *pusing) {
		*pusing = pdel->next;
	}
	else {
		// find the 'pdel' prev node
		struct mplink *p = *pusing;
		while (p != NULL && p->next != pdel) {
			p = p->next;
		}

		if (p == NULL) {
			return -3;
		}

		p->next = pdel->next;
	}

	pdel->next = *pfree;
	*pfree = pdel;
	return 0;
}
#else
static inline int mplink_del(struct mplink **pfree, struct mplink **pusing, void *ptr)
{
	if (*pusing == NULL)
		return -1;

	// find the mplink of 'ptr'
	struct mplink **pwalk = pusing;

	while ((*pwalk)->ptr != ptr) {
		pwalk = &(*pwalk)->next;
	}

	struct mplink *pdel = *pwalk;
	*pwalk = (*pwalk)->next;

	pdel->next = *pfree;
	*pfree = pdel;
	return 0;
}
#endif

static void *mplink_iterator(struct mplink *plist, void *argv[], int argc, \
							int (*callback)(void *ptr, void *argv[], int argc))
{
    struct mplink *p;

    for (p = plist; p != NULL; p = p->next) {
    	if (callback && callback(p->ptr, argv, argc))
    		return p->ptr;
    }
    return NULL;
}


#ifdef __cplusplus
}
#endif

#endif /* __MPLINK_H_ */

